#include "pfs_calculator.h"
#include <omp.h>
#include <vector>
#include <ctime>

using std::vector;

PFS_Calculator::PFS_Calculator(const PFS_Item& pfs_item, double time_limit)
		: pfs_item_(pfs_item), time_limit_(time_limit),
		random_job(0, pfs_item.job_num()-1) {}

void PFS_Calculator::InitResult() {
	#pragma omp critical
	{
		best_solution_ = Solution(0);
		best_score_ = kWorstScore;
	}
}


void PFS_Calculator::PushAnswer(int score,
                                const Solution& solution) {
	if(IsBestScore(score)) {

		#pragma omp critical
		{
			if(IsBestScore(score)) {
				best_score_ = score;
				best_solution_ = solution;
			}
		}

	}
}

int PFS_Calculator::Score(const Solution& solution) const {
	vector<int> endtimes(pfs_item_.machine_num() + 1);
	endtimes.front() = 0; 

	const int first_job = solution.front();
	for (size_t i = 1 ; i < endtimes.size() ; ++i) {
		endtimes[i] = endtimes[i-1] + pfs_item_[i-1][first_job];
	}

	for (size_t i = 1 ; i < solution.size() ; ++i) {  // loop jobs
		for (size_t j = 1 ; j < endtimes.size() ; ++j) {  // loop machines
			endtimes[j] = (endtimes[j-1] > endtimes[j])? endtimes[j-1] :endtimes[j]; // better performance than std::max
			endtimes[j] += pfs_item_[j-1][solution[i]];
		}
	}

	return endtimes.back();
}

auto PFS_Calculator::GetRandomSolution() const -> Solution {
	Solution randomSolution;
	Solution solutionNow;

	for(int i = 0 ; i < pfs_item_.job_num() ; ++i){
		solutionNow.push_back(i);
	}

	for(int i = pfs_item_.job_num() ; i > 0 ; --i)	{
		// for(int i = pfs_item_.job_num() - 1 ; i >= 0 ; --i)	{
		 //int randomIndex = RandomGen<int>(0,i)();
		int randomIndex = rand() % i;
		randomSolution.push_back(solutionNow[randomIndex]);
		solutionNow.erase(solutionNow.begin() + randomIndex);
	}

	return randomSolution;
}

PFS_Calculator::Solution
PFS_Calculator::GetNeighbor(Solution solution) const {
	int a = random_job(), b = random_job();
	while(a == b)
	{ b = random_job(); }

	using std::swap;
	swap(solution[a], solution[b]);	

	return solution;
}